/*
* License:  This  program  is  free  software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by
* the  Free Software Foundation; either version 3 of the License, or (at your
* option)  any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*/

package pcgen.CharacterViewer.resources;

import java.util.ArrayList;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.Parcel;
import android.os.Parcelable;

import pcgen.android.Logger;

import pcgen.CharacterViewer.resources.GameResourceModifier.ModifierTypes;

public class GameResourceAttribute extends GameResourceEx
{
	public GameResourceAttribute()
	{	
	}
	
	public GameResourceAttribute(Parcel in)
	{
		super(in);
	}
	
	public static final Parcelable.Creator<GameResourceAttribute> CREATOR = new Parcelable.Creator<GameResourceAttribute>() 
	{
		public GameResourceAttribute createFromParcel(Parcel in) 
		{
		    return new GameResourceAttribute(in);
		}
		
		public GameResourceAttribute[] newArray(int size) 
		{
		    return new GameResourceAttribute[size];
		}
	};
	
	public void addModifier(GameResourceModifier modifier)
	{
		_modifiers.add(modifier);
	}
	
	public GameResourceModifier addModifier(GameResourceModifier.ModifierTypes type, int value)
	{
		GameResourceModifier modifier = new GameResourceModifier();
		modifier.setModifierType(type);
		modifier.setValue(value);
		
		addModifier(modifier);
		
		return modifier;
	}
	
	public GameResourceAttributeAbility getAbility()
	{
		return getAbility(getAbilityType());
	}
	
	public GameResourceAttributeAbility getAbility(int type)
	{
		switch (type)
		{
			case GameAbilities.Strength:
				return getCharacter().getAbilityStr();
			case GameAbilities.Dexterity:
				return getCharacter().getAbilityDex();
			case GameAbilities.Constitution:
				return getCharacter().getAbilityCon();
			case GameAbilities.Intelligence:
				return getCharacter().getAbilityInt();
			case GameAbilities.Wisdom:
				return getCharacter().getAbilityWis();
			case GameAbilities.Charisma:
				return getCharacter().getAbilityCha();
		}
		
		return null;
	}
	
	public int getAbilityType()
	{
		return _abilityType;
	}
	
	public int getAbilityModifier()
	{
		GameResourceAttribute attribute = getAbility();
		return (attribute != null ? attribute.getAbilityModifier() : 0);
	}
	
	public int getAbilityModifier(int abilityType)
	{
		GameResourceAttribute attribute = getAbility(abilityType);
		return (attribute != null ? attribute.getAbilityModifier() : 0);
	}
	
	public int getMisc()
	{
		return _misc;
	}
	
	public int getModifier()
	{
		int value = 0;
		
		for	(GameResourceModifier modifier : _modifiers)
			value += modifier.getValue();
		
		return value;
	}
	
	public int getModifierTotal()
	{
		return getModifier();
	}
	
	public GameResourceModifier getModifier(int index)
	{
		return _modifiers.get(index);
	}
	
	public int getModifierDamage()
	{
		int value = 0;
		
		for	(GameResourceModifier modifier : _modifiers)
		{
			if (modifier.isDamage())
				value += modifier.getValue();
		}
		
		return value;
	}
	
	public int getModifierHealing()
	{
		int value = 0;
		
		for	(GameResourceModifier modifier : _modifiers)
		{
			if (modifier.isHealing())
				value += modifier.getValue();
		}
		
		return value;
	}
	
	public int getModifierDamageAndHealing()
	{
		int value = 0;
		
		for	(GameResourceModifier modifier : _modifiers)
		{
			if (modifier.isDamage())
			{
				value += modifier.getValue();
				if (getFolder().getSettingsDefenseTypeArmorAsDR())
					value -= getCharacter().getDamageReduction().getValue();
			}
			else if (modifier.isHealing())
				value += modifier.getValue();
		}
		
		return value;
	}
	
	public int getModifierNonDamage()
	{
		int value = 0;
		
		for	(GameResourceModifier modifier : _modifiers)
		{
			if (!modifier.isDamage())
				value += modifier.getValue();
		}
		
		return value;
	}
	
	public int getModifierTemp()
	{
		int value = 0;
		
		for	(GameResourceModifier modifier : _modifiers)
		{
			if (modifier.isTemp())
				value += modifier.getValue();
		}
		
		return value;
	}
	
	public GameResourceModifierList getModifiers()
	{
		return _modifiers;
	}
	
	public String getName()
	{
		return _name;
	}
	
	public Types getType()
	{
		return _type;
	}
	
	public int getValue()
	{
		return _value + getAbilityModifier() + getModifier() + getMisc();
	}
	
	public int getValueBase()
	{
		return _value;
	}
	
	public JSONObject load(JSONObject data)
		throws JSONException
	{
		if (data == null)
			return null;

		setType(Types.valueOf(getJSONString(data, "type")));
		setValue(getJSONInt(data, "value"));
		setMisc(getJSONInt(data, "misc"));
		setAbilityType(getJSONInt(data, "abilityType"));

		_modifiers.clear();
		JSONArray modifiers = data.getJSONArray("modifiers");
		for (int index = 0; index < modifiers.length(); index++)
		{
			if (modifiers.isNull(index))
				continue;
			
			JSONObject itemJSON = modifiers.getJSONObject(index);
			
			GameResourceModifier item = new GameResourceModifier();
			item.load(itemJSON);
			
			_modifiers.add(item);
		}
	    
	    return data;
	}
	
	public void onValueModified()
	{
		if (onValueModifiedIgnore)
			return;
		
		getCharacter().onAttributeChanged();
	}
	
	public void removeModifier(int index)
	{
		if (index >= _modifiers.size())
			return;
		
		_modifiers.remove(index);
	}
	
	public void removeModifier(GameResourceModifier modifier)
	{
		_modifiers.remove(modifier);
	}
	
	public JSONObject save() 
		throws JSONException
	{
	    JSONObject data = new JSONObject();

	    data.put("type", _type.toString());
	    data.put("value", _value);
	    data.put("misc", _misc);
	    data.put("abilityType", _abilityType);
	    data.put("name", _name);
		
		JSONArray modifierJSON = new JSONArray();
		for (GameResourceModifier item : _modifiers)
		{
			JSONObject itemJSON = item.save();
			modifierJSON.put(itemJSON);
		}
		data.put("modifiers", modifierJSON);
	    
	    return data;
	}
	
	public void setAbilityType(int value)
	{
		_abilityType = value;
	}
	
	public void setMisc(int value)
	{
		_misc = value;
	}
	
	public void setName(String value)
	{
		_name = value;
	}
	
	public void setType(Types value)
	{
		_type = value;
	}
	
	public void setValue(int value)
	{
		_value = value;
	}
	
	public void setValue(int value, Types type)
	{
		_value = value;
		_type = type;
	}
	
	public void setValue(int value, int ability, Types type)
	{
		_value = value;
		_abilityType = ability;
		_type = type;
	}
	
	public void setValue(int value, int misc, int ability, Types type)
	{
		_value = value;
		_misc = misc;
		_abilityType = ability;
		_type = type;
	}

	@Override
	protected void readFromParcelTransform(Parcel in) 
		throws Throwable
	{
		try
		{
			setType(Types.valueOf(in.readString()));
			setValue(in.readInt());
			setMisc(in.readInt());
			setAbilityType(in.readInt());
			setName(in.readString());
			
			readFromParcelTransformEx(in);
			
			_modifiers = in.readParcelable(GameResourceModifierList.class.getClassLoader());
		}
		catch (Throwable tr)
		{
			Logger.e(TAG, "readFromParcelTransform", tr);
			throw tr;
		}
	}
	
	protected void readFromParcelTransformEx(Parcel in) 
		throws Throwable
	{
	}
	
	protected void removeDamageAndHealing()
	{
		removeDamageAndHealing(getModifierHealing(), getModifierDamage(), true);
	}
	
	protected void removeDamageAndHealing(int healing, int damage, boolean performCheck)
	{
		if (performCheck)
		{
			if (Math.abs(healing) <= Math.abs(damage))
				return;
		}
		
		// If the value of the healing is greater than or equal to
		// the damage, then clean it out.
		ArrayList<GameResourceModifier> deletion = new ArrayList<GameResourceModifier>();
		for	(GameResourceModifier modifier : getModifiers())
		{
			if ((modifier.getModifierType() == ModifierTypes.Damage) ||
				(modifier.getModifierType() == ModifierTypes.Healing))
				deletion.add(modifier);
		}
		
		for	(GameResourceModifier modifier : deletion)
			removeModifier(modifier);
	}

	@Override
	protected void writeToParcelTransform(Parcel dest, int flags)
		throws Throwable
	{
		try
		{
			dest.writeString(getType().toString());
			dest.writeInt(_value);
			dest.writeInt(_misc);
			dest.writeInt(_abilityType);
			dest.writeString(_name);
			
			writeToParcelTransformEx(dest, flags);
			
			dest.writeParcelable(_modifiers, flags);
		}
		catch (Throwable tr)
		{
			Logger.e(TAG, "writeToParcelTransform", tr);
			throw tr;
		}
	}
	
	protected void writeToParcelTransformEx(Parcel dest, int flags) 
		throws Throwable
	{
	}
	
	protected boolean onValueModifiedIgnore = false;

	private int _abilityType = -1; 
	private int _misc;
	private String _name;
	private Types _type = Types.Other;
	private int _value;
	
	private GameResourceModifierList _modifiers = new GameResourceModifierList();
	
	public enum Types
	{
		Ability,
		Attack,
		Damage,
		Defense,
		Other,
		Save,
		Skill
	}

	private static final String TAG = GameResourceAttribute.class.getSimpleName();
}
